﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Exception = System.Exception;

// 多播组IP地址 (D类地址范围: 224.0.0.0 到 239.255.255.255)
// 224.0.0.0 到 224.0.0.255 为系统保留地址，通常用于路由协议和其他底层网络功能
// 这里选择 239.1.1.1 作为示例
class Program
{
    // // 多播组地址和端口
    // static IPAddress multicastAddress = IPAddress.Parse("224.0.0.168");
    // 多播组地址和端口
    static IPAddress multicastAddress = IPAddress.Parse("234.1.1.42");

    static void Main()
    {
        Console.WriteLine("请选择角色:");
        Console.WriteLine("1. 发送者");
        Console.WriteLine("2. 接收者");
        Console.WriteLine("3. 同时运行发送者和接收者");

        string choice = Console.ReadLine();

        switch (choice)
        {
            case "1":
                RunSender();
                break;
            case "2":
                RunReceiver();
                break;
            case "3":
                // 在不同线程中同时运行发送者和接收者
                Thread senderThread = new Thread(RunSender);
                Thread receiverThread = new Thread(RunReceiver);

                senderThread.Start();
                receiverThread.Start();

                senderThread.Join();
                receiverThread.Join();
                break;
            default:
                Console.WriteLine("无效选择");
                break;
        }
    }

    static void RunSender()
    {
        try
        {
            int port = 11000;
            // 自动获取主网卡的IP地址
            IPAddress? localIp = IPAddress.Parse("192.168.110.121");

            // 创建UDP客户端
            using (UdpClient sender = localIp == null ? new UdpClient() : new UdpClient(new IPEndPoint(localIp, 0)))
                // using (UdpClient sender = new UdpClient())
            {
                // 关键：设置多播回环（同一台机器收发需开启，默认一般是开启，但显式设置更保险）
                sender.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true);
                // 设置多播TTL，同一台机器设1即可，跨网段根据需求加大
                sender.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 1);
                // // 增加TTL值，确保数据包能跨网段传输
                // sender.Client.SetSocketOption(SocketOptionLevel.IP, 
                //     SocketOptionName.MulticastTimeToLive, 2);

                // sender.MulticastLoopback = true; // 允许接收自己发送的多播消息

                Console.WriteLine($"发送者{sender.Client.LocalEndPoint}已启动，输入消息按Enter发送，输入'quit'退出");

                while (true)
                {
                    string message = Console.ReadLine();

                    if (message.ToLower() == "quit")
                        break;

                    // 转换消息为字节数组
                    byte[] data = Encoding.UTF8.GetBytes(message);

                    // 发送数据到多播组
                    sender.Send(data, data.Length, new IPEndPoint(multicastAddress, port));

                    Console.WriteLine($"已发送: {message}");
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"发送者错误: {ex.Message}");
        }
    }

    static void RunReceiver()
    {
        try
        {
            int port = 11000;

            // 创建UDP客户端并绑定到本地端口
            using (UdpClient receiver = new UdpClient(port))
            {
                // // 关键：允许端口复用，同一台机器多个接收端或和发送端避免端口冲突
                // receiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 
                // // 允许其他程序使用相同端口（用于本地测试）
                // receiver.Client.SetSocketOption(SocketOptionLevel.Socket,
                //     SocketOptionName.ReuseAddress, true);

                // receiver.MulticastLoopback = true; // 允许接收自己发送的多播消息
                //
                // // 绑定到所有可用接口
                // receiver.Client.Bind(new IPEndPoint(IPAddress.Any, port));

                // 加入多播组（指定本地接口）
                // // IPAddress.Parse("192.168.110.121")
                // receiver.JoinMulticastGroup(multicastAddress);
                // 加入多播组（指定本地接口）
                receiver.JoinMulticastGroup(multicastAddress,IPAddress.Parse("192.168.110.121"));

                Console.WriteLine($"接收者已启动，等待消息...");

                IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);

                while (true)
                {
                    // 接收数据
                    byte[] data = receiver.Receive(ref remoteEndPoint);

                    // 转换字节数组为字符串
                    string message = Encoding.UTF8.GetString(data);

                    Console.WriteLine($"接收者{receiver.Client.LocalEndPoint}收到来自 {remoteEndPoint}: {message}");
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"接收者错误: {ex.Message}");
        }
    }

// 获取主网卡IP地址的辅助方法
    static IPAddress? GetPrimaryIpAddress()
    {
        try
        {
            // 创建一个临时的UDP连接来发现主网卡
            using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
            {
                // 连接到一个非本地地址（不会实际发送数据）
                socket.Connect("8.8.8.8", 53);

                // 获取本地端点
                IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
                return endPoint.Address;
            }
        }
        catch
        {
            // 尝试备用方法
            try
            {
                string hostName = Dns.GetHostName();
                IPHostEntry hostEntry = Dns.GetHostEntry(hostName);

                foreach (IPAddress ip in hostEntry.AddressList)
                {
                    if (ip.AddressFamily == AddressFamily.InterNetwork &&
                        !IPAddress.IsLoopback(ip))
                    {
                        return ip;
                    }
                }
            }
            catch
            {
            }

            return null;
        }
    }
}


// // See https://aka.ms/new-console-template for more information
//
//
// using System.Net;
// using System.Net.Sockets;
// using System.Text;
// using Makaretu.Dns;
//
//
// // 监听广播 224.0.0.167 的UDP消息
// var multicastAddress  = IPAddress.Parse("224.0.0.167");
// int port = 11111;
//
// using (UdpClient listener = new UdpClient(port))
// {
//     listener.EnableBroadcast = true;
//     listener.JoinMulticastGroup(multicastAddress, IPAddress.Any); // 加入多播组以接收数据
//     IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, port);
//     while (true) // 循环接收数据，实际应用中可能需要某种退出条件
//     {
//         byte[] receivedBytes = listener.Receive(ref remoteEP); // 阻塞直到接收到数据
//         string receivedText = Encoding.UTF8.GetString(receivedBytes);
//         Console.WriteLine("Received: " + receivedText);
//     }
// }
//
// Console.WriteLine("Listening for UDP broadcast messages on port 11111...");
//
// // var list = Dns.GetHostEntry(Dns.GetHostName());
//
// // var list = Dns.GetHostEntry("www.baidu.com");
// //
// //
// // // 接受11111端口的UDP消息
// // // 接收广播
// // var udpReceiveTask = Task.Run(async () =>
// // {
// //     var udpClient = new UdpClient(11111);
// //     while (true)
// //     {
// //         var result = await udpClient.ReceiveAsync();
// //         var message = System.Text.Encoding.UTF8.GetString(result.Buffer);
// //         Console.WriteLine($"Received broadcast message: {message} from {result.RemoteEndPoint}");
// //     }
// // });
// //
// // // 发送11111端口的UDP消息
// // // 发送广播消息
// // var udpSendTask = Task.Run(async () =>
// // {
// //     var udpClient = new UdpClient();
// //     // udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, 0)); // 显式绑定随机端口
// //     // Console.WriteLine("发送端的端口: " + udpClient.Client.LocalEndPoint);
// //     var endpoint = new IPEndPoint(IPAddress.Broadcast, 11111);
// //     while (true)
// //     {
// //         var message = "Hello from mDNS!";
// //         var data = System.Text.Encoding.UTF8.GetBytes(message);
// //         await udpClient.SendAsync(data, data.Length, endpoint);
// //         Console.WriteLine($"Sent broadcast message: {message}");
// //         await Task.Delay(500); // 每5秒发送一次
// //     }
// // });
//
//
//
// // {
// //     var sd = new ServiceDiscovery();
// //     var s = new MulticastService();
// //     // sd.ServiceDiscovered += (s, serviceName) =>
// //     // {
// //     //     Console.WriteLine($"Service discovered: {serviceName}");
// //     //     // Do something };
// //     // };
// //     // sd.ServiceInstanceDiscovered += (s, e) =>
// //     // {
// //     //     // 编码不对
// //     //     // Console.WriteLine($"Service instance discovered: {e.ServiceInstanceName}");
// //     //     var str = string.Join(".", e.ServiceInstanceName.Labels.Select(m => m.ToString()));
// //     //
// //     //     Console.WriteLine($"Service instance discovered: {str}");
// //     //     // Do something };
// //     // };
// //     var service = new ServiceProfile("x", "_foo._tcp", 1024);
// //     if (sd.Probe(service))
// //     {
// //         // Handle the service conflict
// //     }
// //     else
// //     {
// //         //Begin responding to queries for this service
// //         sd.Advertise(service);
// //         //Notify listeners that the service is now available
// //         sd.Announce(service);
// //     }
// // }
//
//
// Console.ReadKey();